package com.killcalorie.wjduan.auth.config

import io.jsonwebtoken.*
import io.jsonwebtoken.security.Keys
import io.jsonwebtoken.security.SignatureException
import org.springframework.beans.factory.annotation.Value
import org.springframework.security.core.userdetails.UserDetails
import org.springframework.stereotype.Component
import java.util.*
import javax.crypto.SecretKey
import org.springframework.stereotype.Service

@Service
class JwtUtil {

    @Value("\${jwt.secret}")
    private lateinit var secret: String

    @Value("\${jwt.expiration}")
    private var expiration: Long = 3600000 // 默认1小时

    private val key: SecretKey by lazy {
        Keys.hmacShaKeyFor(secret.toByteArray())
    }

    /**
     * 生成 JWT 令牌
     * @param userDetails 用户详情
     * @return JWT 令牌字符串
     */
    fun generateToken(userDetails: UserDetails): String {
        return generateToken(userDetails.username)
    }

    /**
     * 生成 JWT 令牌
     * @param username 用户名
     * @return JWT 令牌字符串
     */
    fun generateToken(username: String): String {
        return Jwts.builder()
            .subject(username)
            .issuedAt(Date())
            .expiration(Date(System.currentTimeMillis() + expiration))
            .signWith(key)
            .compact()
    }

    /**
     * 验证 JWT 令牌
     * @param token JWT 令牌
     * @return 是否有效
     */
    fun validateToken(token: String): Boolean {
        return try {
            parseToken(token)
            true
        } catch (ex: Exception) {
            false
        }
    }

    /**
     * 从令牌中提取用户名
     * @param token JWT 令牌
     * @return 用户名
     */
    fun extractUsername(token: String): String {
        return parseToken(token).payload.subject
    }

    /**
     * 使令牌失效
     * @param token JWT 令牌
     */
    fun invalidateToken(token: String) {
        // 在实际应用中，您可能希望将令牌添加到黑名单中
        // 这里只是一个占位符实现
    }

    /**
     * 解析 JWT 令牌
     * @param token JWT 令牌
     * @return Jws<Claims> 对象
     * @throws ExpiredJwtException 令牌过期
     * @throws UnsupportedJwtException 不支持的令牌
     * @throws MalformedJwtException 格式错误的令牌
     * @throws SignatureException 签名验证失败
     * @throws IllegalArgumentException 空或无效令牌
     */
    private fun parseToken(token: String): Jws<Claims> {
        return Jwts.parser()
            .verifyWith(key)
            .build()
            .parseSignedClaims(token)
    }

    /**
     * 获取令牌过期时间
     * @param token JWT 令牌
     * @return 过期时间 (毫秒)
     */
    fun getExpirationFromToken(token: String): Long {
        return parseToken(token).payload.expiration.time
    }

    /**
     * 检查令牌是否即将过期
     * @param token JWT 令牌
     * @param threshold 阈值 (毫秒)，默认30分钟
     * @return 是否即将过期
     */
    fun isTokenExpiringSoon(token: String, threshold: Long = 1800000): Boolean {
        val expiration = getExpirationFromToken(token)
        val currentTime = System.currentTimeMillis()
        return (expiration - currentTime) < threshold
    }

    /**
     * 刷新令牌
     * @param token JWT 令牌
     * @return 新的 JWT 令牌
     */
    fun refreshToken(token: String): String {
        val username = extractUsername(token)
        return generateToken(username)
    }

    /**
     * 从请求头中提取令牌
     * @param authorizationHeader "Authorization" 请求头
     * @return JWT 令牌或 null
     */
    fun extractToken(authorizationHeader: String?): String? {
        return if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) {
            authorizationHeader.substring(7)
        } else {
            null
        }
    }
}